#pragma once
#include <core/container/SHash.h>
#include <core/strings/TinyString.h>
#include <core/sync/lock.h>
#include <qbprotocol/include/SSQBAModel.h>

#include <string>

#include "bondlib.h"
/*
        [内存优化][scofined.qi]
        功能:	只有键值查询,无顺序要求,无迭代要求
        内存优化
                规模: 62428
                尺寸:sizeof(xCSIUint_c)  = 104

        措施:
                1.构建一个新的结构体xCSIUintCompact取代xCSIUint_c,由客户端内部使用,
                    移除xCSIUint_c中的m_bond_key和m_listedmarket字段
                        大小由原先的104减小到52,减少一半
                2.由于主键是CombBondKey,因此可以借鉴BondContainer中的主键表
                        鉴于xCSIUintCompact结构体大小过大,为52,如果使用哈希表,空间浪费严重
                        这种数据结构,最好使用F14Table,后续实现好再替换
                        前期使用map

                        绝大多数ComBondKey可以用ComBondKeyCompact来表示
                        少量的ComBondKey直接用字符串来表示
                        因此,可以将数据放在两个map中
                        简便省事,直接用std::map,每个节点浪费16个字节

                        针对value尺寸过大的容器,都不推荐使用哈希表,会浪费空间
*/
class xCSIUintCompact {
 public:
  xCSIUintCompact() { clear(); }

 public:
  double m_dCleanPriceMaturity;         // 到期净价
  double m_dFullPriceMaturity;          // 到期全价
  double m_dYieldToMaturity;            // 到期收益率
  double m_dModifiedDurationMarturity;  // 到期修正久期

  double m_dCleanPriceExercise;        // 行权净价
  double m_dFullPriceExercise;         // 行权全价
  double m_dYieldToExercise;           // 行权收益率
  double m_dModifiedDurationExercise;  // 行权修正久期

  UINT m_nDate;  // 日期

  xCSIUintCompact(const xCSIUint_c& csiu)
      : m_nDate(csiu.m_nDate),
        m_dCleanPriceMaturity(csiu.m_dCleanPriceMaturity),
        m_dFullPriceMaturity(csiu.m_dFullPriceMaturity),
        m_dYieldToMaturity(csiu.m_dYieldToMaturity),
        m_dModifiedDurationMarturity(csiu.m_dModifiedDurationMarturity),
        m_dCleanPriceExercise(csiu.m_dCleanPriceExercise),
        m_dFullPriceExercise(csiu.m_dFullPriceExercise),
        m_dYieldToExercise(csiu.m_dYieldToExercise),
        m_dModifiedDurationExercise(csiu.m_dModifiedDurationExercise) {}
  xCSIUintCompact& operator=(const xCSIUint_c& csiu) {
    m_nDate = csiu.m_nDate;
    m_dCleanPriceMaturity = csiu.m_dCleanPriceMaturity;
    m_dFullPriceMaturity = csiu.m_dFullPriceMaturity;
    m_dYieldToMaturity = csiu.m_dYieldToMaturity;
    m_dModifiedDurationMarturity = csiu.m_dModifiedDurationMarturity;
    m_dCleanPriceExercise = csiu.m_dCleanPriceExercise;
    m_dFullPriceExercise = csiu.m_dFullPriceExercise;
    m_dYieldToExercise = csiu.m_dYieldToExercise;
    m_dModifiedDurationExercise = csiu.m_dModifiedDurationExercise;
    return *this;
  }
  void GetCSIU(xCSIUint_c& csiu) {
    csiu.m_nDate = m_nDate;
    csiu.m_dCleanPriceMaturity = m_dCleanPriceMaturity;
    csiu.m_dFullPriceMaturity = m_dFullPriceMaturity;
    csiu.m_dYieldToMaturity = m_dYieldToMaturity;
    csiu.m_dModifiedDurationMarturity = m_dModifiedDurationMarturity;
    csiu.m_dCleanPriceExercise = m_dCleanPriceExercise;
    csiu.m_dFullPriceExercise = m_dFullPriceExercise;
    csiu.m_dYieldToExercise = m_dYieldToExercise;
    csiu.m_dModifiedDurationExercise = m_dModifiedDurationExercise;
  }
  void clear() {
    m_dCleanPriceMaturity = _INVALID_CSI_VALUE;
    m_dFullPriceMaturity = _INVALID_CSI_VALUE;
    m_dYieldToMaturity = _INVALID_CSI_VALUE;
    m_dModifiedDurationMarturity = _INVALID_CSI_VALUE;

    m_dCleanPriceExercise = _INVALID_CSI_VALUE;
    m_dFullPriceExercise = _INVALID_CSI_VALUE;
    m_dYieldToExercise = _INVALID_CSI_VALUE;
    m_dModifiedDurationExercise = _INVALID_CSI_VALUE;
    memset(this, 0, sizeof(xCSIUint_c));
  }

  inline bool IsHaveYieldToExercise() {
    return m_dYieldToExercise > _INVALID_CSI_VALUE;
  }
  inline bool IsHaveCleanPriceExercise() {
    return m_dCleanPriceExercise > _INVALID_CSI_VALUE;
  }
  inline bool IsHaveFullPriceExercise() {
    return m_dFullPriceExercise > _INVALID_CSI_VALUE;
  }
  inline bool IsModifiedDurationExercise() {
    return m_dModifiedDurationExercise > _INVALID_CSI_VALUE;
  }

  inline bool IsHaveYieldToMarturity() {
    return m_dYieldToMaturity > _INVALID_CSI_VALUE;
  }
  inline bool IsHaveCleanPriceMarturity() {
    return m_dCleanPriceMaturity > _INVALID_CSI_VALUE;
  }
  inline bool IsHaveFullPriceMarturity() {
    return m_dFullPriceMaturity > _INVALID_CSI_VALUE;
  }
  inline bool IsModifiedDurationMarturity() {
    return m_dModifiedDurationMarturity > _INVALID_CSI_VALUE;
  }

  inline bool IsHaveExercise() {
    return (IsHaveYieldToExercise() || IsHaveCleanPriceExercise() ||
            IsModifiedDurationExercise() || IsHaveFullPriceExercise())
               ? true
               : false;
  }

  inline bool IsHaveMarturity() {
    return (IsHaveYieldToMarturity() || IsHaveCleanPriceMarturity() ||
            IsModifiedDurationMarturity() || IsHaveFullPriceMarturity())
               ? true
               : false;
  }
};

class S_BONDLIB_EXPORT CBondCSInfo {
 public:
  static CBondCSInfo& instance();
  /*
          之所以没有使用KeyString替换std::string,是因为
          GetBondCsiDate中参数类型是std::string,
          改为KeyString后,每次查找都会额外引入一次KeyString分配的开销
          使用TinyString,查找的时候构建伪造一个轻量级的TempTinyString
          无需内存分配,析构的时候也不需要释放内存
  */
  typedef qb::base::TinyString KeyType;
  struct KeyTypeHasher {
    size_t operator()(const KeyType& key) const {
      return qb::base::time33Hash(key.c_str(), key.size());
    }
  };

  // 以下两种实现皆可,看哪种更省空间,选取一种,将另一种注释掉即可
  // 注意,如果是哈希表,需要考虑逐步扩充,此容器的规模是6w+,map则不用考虑
  typedef std::map<KeyType, xCSIUintCompact> CSInfoMap;
  // typedef std::unordered_map<KeyType, xCSIUintCompact, KeyTypeHasher>
  // CSInfoMap;

  // 以下是改进之前的容器,浪费较为严重
  // typedef std::unordered_map<std::string, xCSIUint_c> UMAP_CSI;
  enum emCSIType {
    emCSITypeNull,
    emCSITypeCombine,
    emCSITypeExercise,
    emCSITypeMaturity,
  };
  enum kPriceType {
    price_type_yield = 0,  // 中证估值收益率
    price_type_clean,      // 中证估值净价
    price_type_duration,   // 中证估值久期
    price_type_full,       // 中证估值全价
  };

 public:
  qb::base::CSLock& GetMutex() { return m_mutex; }

  void clear();

  void add(const xCSIList_c* pList);

  UINT GetBondCsiDate(const std::string& sCombondkey);

  static std::string BuildCombondkey(const std::string& sBondKey,
                                     const std::string& sLisMakert);

  bool GetCsiUnit(const std::string& sCombondkey, xCSIUint_c& xUnit);

  double GetCsiYieldForSort(const std::string& sCombondkey);
  double GetCsiCleanPriceForSort(const std::string& sCombondkey);
  double GetCsiFullPriceForSort(const std::string& sCombondkey);

 protected:
  CSInfoMap m_umapCsi;
  qb::base::CSLock m_mutex;

  const std::string m_sSlash;

 private:
  CBondCSInfo();
  ~CBondCSInfo();
};
